package com.imooc.filter;

import com.google.gson.Gson;
import com.imooc.base.BaseInfoProperties;
import com.imooc.grace.result.GraceJSONResult;
import com.imooc.grace.result.ResponseStatusEnum;
import com.imooc.utils.JWTUtils;
import io.jsonwebtoken.ExpiredJwtException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 全局登录过滤器
 */
@Component
@Slf4j
public class SecurityFilterJWT extends BaseInfoProperties implements GlobalFilter, Ordered {

    @Autowired
    private ExcludeUrlPathProperties excludeUrlPathProperties;
    @Autowired
    private JWTUtils jwtUtils;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private static final String HEADER_USER_TOKEN = "headerUserToken";

    /**
     * 判断当前请求访问的接口是否携带JWTToken
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 1. 获得当前请求的url
        String url = exchange.getRequest().getURI().getPath();

        // 2. 获取所有需要排除校验的url
        List<String> excludeList = excludeUrlPathProperties.getUrls();
        if (excludeList != null && excludeList.contains(url)) {
            for (String excludeUrl : excludeList) {
                // 不需要JWTToken，可以直接访问的接口
                if (antPathMatcher.match(excludeUrl, url)) {
                    return chain.filter(exchange);
                }
            }
        }

        // 需要进行JWTToken校验的接口，如果校验通过放行


//  debug     if(Objects.equals(url, "/saas/scanCode")){
//            System.out.println(1);
//        }

        HttpHeaders headers = exchange.getRequest().getHeaders();
        String userToken = headers.getFirst(HEADER_USER_TOKEN);

        if (StringUtils.isNotBlank(userToken)) {
            String[] tokenArr = userToken.split(JWTUtils.at);
            if (tokenArr.length != 2) {
                return renderErrorMsg(exchange, ResponseStatusEnum.UN_LOGIN);
            }

            String prefix = tokenArr[0];
            String jwt = tokenArr[1];

            switch (prefix) {
                case TOKEN_USER_PREFIX:
                    return dealToken(jwt, exchange, chain, APP_USER_JSON);
                case TOKEN_SAAS_PREFIX:
                    return dealToken(jwt, exchange, chain, SAAS_USER_JSON);
                case TOKEN_ADMIN_PREFIX:
                    return dealToken(jwt, exchange, chain, ADMIN_USER_JSON);
            }
        }
        return renderErrorMsg(exchange, ResponseStatusEnum.UN_LOGIN);
    }

    private Mono<Void> dealToken(String jwt, ServerWebExchange exchange, GatewayFilterChain chain, String key) {
        try {
            String userJson = jwtUtils.checkJWT(jwt);

            // userJson存到请求头中，方便在controller、service中使用
            ServerWebExchange serverWebExchange = setNewHeader(exchange, key, userJson);
            return chain.filter(serverWebExchange);
        } catch (ExpiredJwtException e) {
            log.error(e.getMessage());
            return renderErrorMsg(exchange, ResponseStatusEnum.JWT_EXPIRE_ERROR);
        } catch (Exception e) {
            log.error(e.getMessage());
            return renderErrorMsg(exchange, ResponseStatusEnum.JWT_SIGNATURE_ERROR);
        }
    }

    /**
     * 在请求头中添加信息
     */
    private ServerWebExchange setNewHeader(ServerWebExchange exchange,
                                           String headerKey, String headerValue) {
        // 重新构建新的request
        ServerHttpRequest request = exchange.getRequest()
                .mutate().header(headerKey, headerValue).build();

        // 替换原来的request
        return exchange.mutate().request(request).build();
    }

    /**
     * 重新包装并返回错误信息
     */
    private Mono<Void> renderErrorMsg(ServerWebExchange exchange, ResponseStatusEnum responseStatusEnum) {
        // 1. 获得response
        ServerHttpResponse response = exchange.getResponse();
        // 2. 构建jsonResult
        GraceJSONResult graceJSONResult = GraceJSONResult.exception(responseStatusEnum);
        // 3. 修改response的code为500
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        // 4. 设定header类型
        if (!response.getHeaders().containsKey("Content-Type")) {
            response.getHeaders().add("Content-Type", MimeTypeUtils.APPLICATION_JSON_VALUE);
        }
        // 5. 转换json并且向response中写入数据
        String resultJson = new Gson().toJson(graceJSONResult);
        DataBuffer dataBuffer = response.bufferFactory().wrap(resultJson.getBytes(StandardCharsets.UTF_8));

        return response.writeWith(Mono.just(dataBuffer));
    }


    // 过滤器的顺序，数字越小优先级越大
    @Override
    public int getOrder() {
        return 0;
    }
}
